// Package static provides a static registry
// 无注册中心情况下配置使用，各服务地址，通过配置方式提供
package static

import (
	"errors"
	"io/ioutil"

	"gopkg.in/yaml.v2"

	"sync"
	//"time"

	"github.com/micro/go-micro/v2/config/cmd"
	"github.com/micro/go-micro/v2/registry"

	//"github.com/micro/go-micro/v2/util/log"
	log "github.com/micro/go-micro/v2/logger"
)

var (
	prefix                = "/hms-registry"
	ERR_SERVICE_NOT_FOUND = errors.New("Service Not Found")
)

type staticRegistry struct {
	options registry.Options
	sync.Mutex
	register map[string]uint64

	//param for registry
	params map[string]string
	//serviceList  map[string]*registry.Service
	regCfg *registerConfig
}

func init() {
	cmd.DefaultRegistries["static"] = NewRegistry
}

func configure(z *staticRegistry, opts ...registry.Option) error {
	log.Info("==configure=========================")

	return nil
}

func (z *staticRegistry) Init(opts ...registry.Option) error {
	log.Info("==Init=========================")
	return configure(z, opts...)
}

func (z *staticRegistry) Options() registry.Options {
	return z.options
}

//func (z *staticRegistry) Deregister(s *registry.Service) error {
func (z *staticRegistry) Deregister(s *registry.Service, opts ...registry.DeregisterOption) error {
	log.Debug("==Deregister=========================")
	if len(s.Nodes) == 0 {
		return errors.New("Require at least one node")
	}

	for _, n := range s.Nodes {
		log.Warn("[static DeRegister node]:", *n)
	}
	return nil
}

func (z *staticRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
	log.Debug("==Register=========================", *s)

	if len(s.Nodes) == 0 {
		return errors.New("Require at least one node")
	}

	var options registry.RegisterOptions
	for _, o := range opts {
		o(&options)
	}
	//log.Error("==Register Option=========================", z.params)

	//for _, n := range s.Nodes {
	//	//log.Warn("[static Register node]:", *n)
	//}

	return nil
}

/*
   type Service struct {
   	Name      string            `json:"name"`
   	Version   string            `json:"version"`
   	Metadata  map[string]string `json:"metadata"`
   	Endpoints []*Endpoint       `json:"endpoints"`
   	Nodes     []*Node           `json:"nodes"`
   }

	type Node struct {
		Id       string            `json:"id"`
		Address  string            `json:"address"`
		Metadata map[string]string `json:"metadata"`
	}

*/
func (z *staticRegistry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) {
	var options registry.GetOptions
	for _, o := range opts {
		o(&options)
	}

	services := make([]*registry.Service, 0, 1)
	var err error = nil
	if service, ok := z.regCfg.Services[name]; ok {
		//return services, nil
		//log.Error("GetService", service.Nodes[0])
		services = append(services, service)
	} else {
		services = nil
		err = ERR_SERVICE_NOT_FOUND
	}
	//log.Error("GetService", services)
	return services, err
}

func (z *staticRegistry) ListServices(opts ...registry.ListOption) ([]*registry.Service, error) {
	log.Debug("==ListServices=========================")

	var registryServices []*registry.Service
	for _, v := range z.regCfg.Services {
		registryServices = append(registryServices, v)
	}
	return registryServices, nil
}

func (z *staticRegistry) String() string {
	return "static"
}

func (z *staticRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
	log.Debug("==Watch=========================", len(opts))

	//return newstaticWatcher(z, opts...)

	return nil, errors.New("Watch unimplement")
}

func NewRegistry(opts ...registry.Option) registry.Registry {
	var options registry.Options
	for _, o := range opts {
		o(&options)
	}

	if options.Timeout == 0 {
		options.Timeout = 5
	}
	params := make(map[string]string)

	if nil != options.Context {
		p := options.Context.Value("params")
		if pp, ok := p.(map[string]string); ok {
			params = pp
		}
	}
	log.Info("==param================================", params)

	regCfg := newRegisterConfig()
	if serviceFile, ok := params["servicefile"]; ok {
		//defGroupName = groupName
		// 如果配置服务文件，需要加载
		cfgErr := regCfg.load(serviceFile)
		if nil != cfgErr {
			log.Error("static register load config error:", cfgErr)
		}
	}

	return &staticRegistry{
		options:  options,
		register: make(map[string]uint64),
		params:   params,
		regCfg:   regCfg,
	}
}

type registerConfig struct {
	Params   map[string]string            `yaml:"params"`   //配置参数
	Services map[string]*registry.Service `yaml:"services"` //服务列表
}

func newRegisterConfig() *registerConfig {
	regCfg := new(registerConfig)
	regCfg.Params = make(map[string]string)
	regCfg.Services = make(map[string]*registry.Service)

	return regCfg
}

func (rc *registerConfig) load(fileName string) error {

	data, err := ioutil.ReadFile(fileName)
	if nil != err {
		log.Error("load registerConfig error", err)
	} else {
		err = yaml.Unmarshal(data, rc)
		log.Info(rc)
		for k, r := range rc.Services {
			log.Infof("static [%s]: [%v]", k, r)
		}
	}

	return err
}
